package handler

import (
	"context"
	"errors"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"gorm.io/gorm"

	els "mxshop_srvs/goods_srv/dao/elasticsearch"
	"mxshop_srvs/goods_srv/model"
	proto "mxshop_srvs/goods_srv/proto/gen/v1"
)

func ModelToResponse(goods model.Goods) proto.GoodsInfoResponse {
	return proto.GoodsInfoResponse{
		Id:              goods.ID,
		CategoryId:      goods.CategoryID,
		Name:            goods.Name,
		GoodsSn:         goods.GoodsSn,
		ClickNum:        goods.ClickNum,
		SoldNum:         goods.SoldNum,
		FavNum:          goods.FavNum,
		MarketPrice:     goods.MarketPrice,
		ShopPrice:       goods.ShopPrice,
		GoodsBrief:      goods.GoodsBrief,
		ShipFree:        goods.ShipFree,
		GoodsFrontImage: goods.GoodsFrontImage,
		IsNew:           goods.IsNew,
		IsHot:           goods.IsHot,
		OnSale:          goods.OnSale,
		DescImages:      goods.DescImages,
		Images:          goods.Images,
		Category: &proto.CategoryBriefInfoResponse{
			Id:   goods.Category.ID,
			Name: goods.Category.Name,
		},
		Brand: &proto.BrandInfoResponse{
			Id:   goods.Brands.ID,
			Name: goods.Brands.Name,
			Logo: goods.Brands.Logo,
		},
	}
}

func (s *Service) CreateGoods(_ context.Context, req *proto.CreateGoodsInfo) (*proto.GoodsInfoResponse, error) {
	goodsID, err := s.DB.CreateGoods(req)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.NotFound, "")
		}
		return nil, status.Errorf(codes.Internal, "")
	}
	return &proto.GoodsInfoResponse{
		Id: goodsID,
	}, nil
}

func (s *Service) GoodsList(ctx context.Context, req *proto.GoodsFilterRequest) (*proto.GoodsListResponse, error) {
	var categoryLevel int32
	if req.TopCategory > 0 { // 查询是否有该分类
		category, err := s.DB.GetCategory(req.TopCategory)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, status.Error(codes.NotFound, "")
			}
			return nil, status.Errorf(codes.Internal, "")
		}
		categoryLevel = category.Level
	}

	// 调用repository层
	// count, goodsList, err := s.DB.GoodsList(req, categoryLevel)
	count, goodsList, err := s.GoodsRepo.GetGoodsList(ctx, req, categoryLevel)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) || errors.Is(err, els.NotFound) {
			return nil, status.Error(codes.NotFound, "")
		}
		return nil, status.Errorf(codes.Internal, "")
	}

	var data []*proto.GoodsInfoResponse
	for _, goods := range goodsList {
		goodsInfoResponse := ModelToResponse(goods)
		data = append(data, &goodsInfoResponse)
	}
	return &proto.GoodsListResponse{
		Total: count,
		Data:  data,
	}, nil
}

func (s *Service) BatchGetGoods(_ context.Context, req *proto.BatchGoodsIdInfo) (*proto.GoodsListResponse, error) {
	total, goodsList, err := s.DB.BatchGetGoods(req.Id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.NotFound, "")
		}
		return nil, status.Errorf(codes.Internal, "")
	}
	var data []*proto.GoodsInfoResponse
	for _, goods := range goodsList {
		goodsInfo := ModelToResponse(goods)
		data = append(data, &goodsInfo)
	}
	return &proto.GoodsListResponse{
		Total: int32(total),
		Data:  data,
	}, nil
}

func (s *Service) GetGoodsDetail(_ context.Context, req *proto.GoodInfoRequest) (*proto.GoodsInfoResponse, error) {
	goods, err := s.DB.GetGoodsByID(req.Id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.NotFound, "商品不存在")
		}
		return nil, status.Errorf(codes.Internal, "")
	}
	goodsInfo := ModelToResponse(goods)
	return &goodsInfo, nil
}

func (s *Service) UpdateGoods(_ context.Context, req *proto.CreateGoodsInfo) (*emptypb.Empty, error) {
	goods, err := s.DB.GetGoodsByID(req.Id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.NotFound, "")
		}
		return nil, status.Errorf(codes.Internal, "")
	}

	if req.CategoryId > 0 {
		_, err := s.DB.GetCategory(req.CategoryId)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, status.Error(codes.InvalidArgument, "must be the correct category id")
			}
			return nil, status.Errorf(codes.Internal, "")
		}
	}

	if req.BrandId > 0 {
		_, err := s.DB.BrandExistsByID(req.BrandId)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, status.Error(codes.InvalidArgument, "must be the correct brand id")
			}
			return nil, status.Errorf(codes.Internal, "")
		}
	}

	_, err = s.DB.UpdateGoods(goods, req)
	if err != nil {
		return nil, err
	}
	return &emptypb.Empty{}, nil
}

func (s *Service) DeleteGoods(_ context.Context, req *proto.DeleteGoodsInfo) (*emptypb.Empty, error) {
	rowsAffected, err := s.DB.DeleteGoods(req.Id)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if rowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "")
	}
	return &emptypb.Empty{}, nil
}
